CORS (Cross-Origin Resource Sharing) in Next.js Route Handlers is handled by manually setting HTTP headers on responses. Unlike Express which has the 'cors' middleware, Next.js Route Handlers require you to set headers explicitly — either per route or globally via a helper function or middleware.
CORS errors occur when a browser blocks a request made from one origin (e.g. http://localhost:3000) to a different origin (e.g. https://api.example.com). In Next.js Route Handlers, you control CORS entirely through response headers — there is no built-in CORS middleware like Express has.
Access-Control-Allow-Origin — which origins can access the resource (* for all, or specific origin)
Access-Control-Allow-Methods — which HTTP methods are allowed (GET, POST, PUT, DELETE, OPTIONS)
Access-Control-Allow-Headers — which request headers are allowed (Content-Type, Authorization)
Access-Control-Allow-Credentials — whether cookies/auth headers can be sent (true/false)
Access-Control-Max-Age — how long preflight response can be cached in seconds
Access-Control-Expose-Headers — which headers are exposed to the browser
Forgetting to handle OPTIONS preflight — POST/PUT/DELETE will silently fail in browser
Using '*' with credentials — browser blocks it, must use exact origin with Allow-Credentials
Setting CORS headers only on success responses — errors (4xx, 5xx) also need CORS headers or browser won't show the error
Not including all required headers in Access-Control-Allow-Headers that the client sends
Hardcoding origins in every route — use a helper or middleware to keep it DRY
Confusing server-to-server requests with browser requests — CORS only applies to browsers
Per-route headers — simple, explicit, good for 1-2 routes with different CORS needs
Shared helper function — DRY, good for medium apps with consistent CORS policy
Global middleware — best for large apps, applies CORS to all API routes automatically
next.config.js headers — good for simple static CORS headers but cannot inspect origin dynamically